/***********************************************************************
 * Module:  Partie.java
 * Author:  nabil
 * Purpose: Defines the Class Partie
 ***********************************************************************/
package model.gestion_jeu;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Observable;
import model.jeu_de_dame.Case;
import model.jeu_de_dame.Damier;
import model.jeu_de_dame.Piece;
import model.util.Couleur;

 /**
 * <b>Partie est la classe principale de notre jeu qui contient les éléments du jeu et les joueurs.
 *    Cette classe hérite de partie model, et implemente donc Observable.
 * </b>
 * <p>
 * Une partie est caractérisé par les informations suivantes :
 * <ul>
 * <li>Un Joueur qui possède des pions blancs.</li>
 * <li>Un Joueur qui possède des pions noirs.</li>
 * <li>Un damier</li>
 * </ul>
 * </p>
 * 
 * @see Damier
 * @see PartieModel
 * @see Observable
 * @see Joueur
 * @author nabil mansouri
 * @version 2.0
 */
public class Partie extends PartieModel implements Serializable {

   /**
         * Le Joueur "blanc" c'est à dire qui possède les pions blancs.
         * 
         * @see Partie#Partie(String, String)
         * @see Partie#getJoueurBlanc()
         */
   protected Joueur blanc;
   /**
         * Le Joueur "noir" c'est à dire qui possède les pions noirs.
         * 
         * @see Partie#Partie(String, String)
         * @see Partie#getJoueurNoir()
         */
   protected Joueur noir;
   /**
         * Le Damier "damier" c'est le jeu avec les élèments du jeu
         * 
         * @see Partie#Partie(String, String)
         * @see Partie#initialisation()
         * @see Partie#getDamier()
         */
   protected Damier damier;

    public Partie() {
        damier = new Damier();
    }
   
    /**
         * Constructeur Partie.
         * <p>
         * A la construction d'un objet Partie, le Damier est crée. De plus le Joueur blan et
         * le Joueur noir sont crées et ont respectivement pour nom "nomBlanc", "nomNoir".
         * La valeur "tour" du joueur blanc est mis à vrai, ce sera à lui qui pourra jouer le premier.
         * </p>
         * 
         * @param nomBlanc
         *            Le nom du Joueur blanc
         * @param nomNoir
         *            Le nom du Joueur noir
         * 
         * @see Partie#blanc
         * @see Partie#noir
         * @see Partie#damier
         */
   
   public Partie(String nomBlanc, String nomNoir)
   {
        try {
            damier = new Damier();
            this.blanc = FactoryJoueur.getInstance().createJoueur(FactoryJoueurIF.Type.REEL, this, nomBlanc);
            this.noir = FactoryJoueur.getInstance().createJoueur(FactoryJoueurIF.Type.REEL, this, nomNoir);
            blanc.setTour(true);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
   }

    public Partie(String nomNoir) {
        try {
            damier = new Damier();
            this.blanc = FactoryJoueur.getInstance().createJoueur(FactoryJoueurIF.Type.VIRTUELLE, this, "Ordinateur");
            this.noir = FactoryJoueur.getInstance().createJoueur(FactoryJoueurIF.Type.REEL, this, nomNoir);
            blanc.setTour(true);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
   
     public Partie(Format f) {
       damier = new Damier();
       blanc = f.getBlanc();
       noir = f.getNoir();
       damier.setMesPieces(f.getLesPieces());
    }
   
   
   
   /**
         * Initialise le damier ainsi que ses cases et ses pions puis notifie les observateurs d'un changement.   
         * 
         * @see Partie#damier
         */
   public void initialisation()
    {
        damier.initialisation();
        this.setChanged();
        this.notifyObservers();
    }
   
    /**
         * Renvoie le Joueur pour lequel son tour est arrivé.
         * 
         * @see Partie#noir
         * @see Partie#blanc 
        * @return Le joueur à qui le tour est arrivé 
     */
   public Joueur getJoueurTour()
   {//la couleur du joueur a qui le tour de jouer
       if(blanc.isMonTour())
           return blanc;
       else
           return noir;
   }
   
   /**
         * Retourne le damier
         * 
         * @see Partie#damier
        * @return Le damier de la partie
     */
   public Damier getDamier()
   {
       return this.damier;
   } 
   
    /**
         * Retourne le joueur blanc de la partie
         * 
         * @see Partie#blanc
        * @return Le joueur blanc de la partie
     */
  public Joueur getJoueurBlanc()
  {
      return blanc;
  }
  
      /**
         * Retourne le joueur noir de la partie
         * 
         * @see Partie#noir
        * @return Le joueur noir de la partie
     */
  public Joueur getJoueurNoir()
  {
      return noir;
  }

   /**
     * Notifie les observateurs de la partie qu'un changement a été fait et qu'ils doivent se mettre à jour
     * 
     * @see Observable
     */
  public void maj()
  {
      this.damier.maj();
      this.blanc.maj();
      this.noir.maj();
      this.setChanged();
      this.notifyObservers();
  }
  
       /**
         * Retourne vrai si la partie est finie, faux sinon. La partie est finie si un des deux 
         * joueurs n'a plus de pions 
         * 
         * @see Partie#blanc 
         * @see Partie#noir
        * @return Vrai si la partie est finie faux sinon
     */
      public boolean isFinie()
      {
          return this.damier.getNbPionBlanc()==0 || this.damier.getNbPionNoir() == 0;
      }
  
         /**
         * Retourne le joueur qui a gagné la partie si la partie est finie.
         * Si la partie n'est pas finie,renvoie null. 
         * 
         * @see Partie#blanc 
         * @see Partie#noir
         * @see Partie#isFinie() 
        * @return Le joueur gagnant si la partie est finie, null sinon.
     */
  public Joueur getVainqueur()
  {
     if(isFinie())
     {
         if(damier.getNbPionBlanc()==0)
             return noir;
         else
             return blanc;
     }
     return null;
  }

  
     /**Cette méthode vérifie si la piece séléctionnée existe et peut être selectionnée.
    * Pour celà il faut que la pièce soit celle du joueur, qu'elle existe et qu'il n'y ait pas 
    * d'autre pièce déjà selectionnée
    * @param x
    *       la coordonnée x de la piece selectionne
    * @param y 
    *       la coordonnée y de la piece selectionnée
    * 
     * @return La piece selectionnée
     */
   public  Piece selectionPion(int x, int y)
    {
        try
        {
            Piece p = this.damier.getPiece(x, y);
            if(p.getCouleur()==this.getCouleurTour() && p.peutBouger())
            {
                p.setSelected(true);
                this.maj();
                return p;
            }
            return null;
        }catch(Exception e)
        {
            return null;
        }
    }
   
   public Couleur getCouleurTour()
   {
       if(blanc.isMonTour())
           return Couleur.BLANC;
       else
           return Couleur.NOIR;
   }
   
   public boolean selectionCase( int xCase, int yCase, Piece p)
   {
        try {
            Case arrive = this.getDamier().getCase(xCase, yCase);
            if(!p.getCasesAccessibles().contains(arrive))
                return false;
            if(p.seDeplacer(arrive))
            {//si je n ai pas manger ou je ne peut plus manger ce n'est plus mon tour
                if(!p.aManger() || !p.peutManger())
                {
                    this.changerTour();
                    p.setSelected(false);
                }
                this.maj();
                return true;
            }
            return false;
        } catch (Exception ex) {
           return false;
        }
   }
   
   public void changerTour()
   {
       if(this.getJoueurBlanc().isMonTour())
       {
           this.getJoueurBlanc().setTour(false);
           this.getJoueurNoir().setTour(true);
       }
       else
       {
           this.getJoueurBlanc().setTour(true);
           this.getJoueurNoir().setTour(false);
       }
   }
   
   public void save()
   {
       Format f = new Format(getJoueurBlanc(), getJoueurNoir(), damier.getMesPieces(), damier.getCouleurJeu());
       f.setMaPartie(this);
       AdaptateurSauvvegarde.getInstance().sauvegarder(f);
   }
   
   public ArrayList<Piece> getPieces(Joueur j)
   {
       if(j==blanc)
           return damier.getPieces(Couleur.BLANC);
       else
           return damier.getPieces(Couleur.NOIR);
           
   }
}